#include "stdafx.h"
#include "EXDropListComboBox.h"
#include "EXScrollBar.h"


// CEXDropListComboBox

IMPLEMENT_DYNAMIC(CEXDropListComboBox, CComboBox)

CEXDropListComboBox::CEXDropListComboBox()
{
	m_nComboTopHeight = 0;
	m_nComboBottomHeight = 0;
	m_nComboLeftWidth = 0;
	m_nComboRightWidth = 0;
	m_nComboBkgndID = 0;
	m_nComboNumOfBgPics = 0;
	m_crTransparent = RGB(255, 0, 255); 
	m_crComboBkgnd = RGB(255,255,255);
	m_crListNormal = RGB(206,209,226);
	m_crListFocus = RGB(49, 106, 197);
	m_bSetComboBg = FALSE;
	m_bSelect = FALSE;
	m_bSetFont = FALSE;
	m_pScroll = NULL;
}

CEXDropListComboBox::~CEXDropListComboBox()
{
	if (m_pScroll)
		delete m_pScroll;
}


BEGIN_MESSAGE_MAP(CEXDropListComboBox, CComboBox)
	ON_WM_SIZE()
	ON_CONTROL_REFLECT(CBN_CLOSEUP, &CEXDropListComboBox::OnCbnCloseup)
	ON_CONTROL_REFLECT(CBN_DROPDOWN, &CEXDropListComboBox::OnCbnDropdown)
	ON_WM_ERASEBKGND()
	ON_WM_NCPAINT()
	ON_WM_PAINT()
	ON_WM_MOUSEWHEEL()
END_MESSAGE_MAP()



// CEXDropListComboBox message handlers

BOOL CEXDropListComboBox::CursorInWindow()
{
	POINT ptCur;
	if (GetCursorPos(&ptCur))
	{
		ScreenToClient(&ptCur);

		CRect rcWnd;
		GetWindowRect(rcWnd);
		ScreenToClient(rcWnd);

		if (rcWnd.PtInRect(ptCur))
			return TRUE;
	}
	return FALSE;
}

void CEXDropListComboBox::SetResSet(CEXBaseResSet* pResSet)
{
  m_pComboResSet = (CEXDropListComboBoxResSet *)pResSet;
 
  SetFont(m_pComboResSet->m_font);
  SetListColor(m_pComboResSet->m_crNormal, m_pComboResSet->m_crFocus);

  if(m_pComboResSet->m_nType == LISTDOWN_COMBO_CTRL)
    SetComboBgBitmaps(m_pComboResSet->m_arrImgId.GetAt(0), 
                      m_pComboResSet->m_arrImgId.GetAt(1), 
                      m_pComboResSet->m_nImg_DivideCnt, 
                      m_crComboBkgnd,4,4,4,20);
}


void CEXDropListComboBox::DrawFrame(CDC * pDC)
{
	if (!m_bSetComboBg)
		return;

	BOOL bAlloc = FALSE;
	if (!pDC)
	{
		bAlloc = TRUE;
		pDC = GetDC();
	}

	CRect rcClient;
	GetClientRect(rcClient);

	CDC dcBkgnd;
	dcBkgnd.CreateCompatibleDC(pDC);

	CBitmap bmpBkgnd;
	bmpBkgnd.CreateCompatibleBitmap(pDC, rcClient.Width(), rcClient.Height());

	CBitmap * pOldBmpBkgnd = NULL;
	pOldBmpBkgnd = dcBkgnd.SelectObject(&bmpBkgnd);

	CDC dcImage;
	dcImage.CreateCompatibleDC(pDC);

	CBitmap* pOldBgBitmapImage = NULL;

	STATUS st;

	if (!IsWindowEnabled())
		st = disable;
	else if (m_bSelect)
		st = select;
	else if (CursorInWindow())
		st = focus;
	else
		st = normal;

	pOldBgBitmapImage  = dcImage.SelectObject(&m_bmpBkgnd);

	//dcBkgnd.TransparentBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcImage, 0, 0, rcClient.Width(), rcClient.Height(), m_crComboBkgnd);
	dcBkgnd.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcImage, rcClient.Width()*st, 0, SRCCOPY);
	dcImage.SelectObject(pOldBgBitmapImage);

	pDC->TransparentBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcBkgnd, 0, 0, rcClient.Width(), rcClient.Height(), m_crTransparent);
//	pDC->BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcBkgnd, 0, 0, SRCCOPY);
	dcBkgnd.SelectObject(pOldBmpBkgnd);

	int nSel = GetCurSel();
	if (nSel != CB_ERR)
	{
		rcClient.DeflateRect(5, 2, 25, 2);
		MyDrawTextEx(pDC, nSel, &rcClient);
	}

	if (bAlloc)
		ReleaseDC(pDC);
}

void CEXDropListComboBox::MyDrawTextEx(CDC * pDC, int nIndex, CRect * prcText)
{
	CString strItem;
	GetLBText(nIndex, strItem);

	if (!strItem.IsEmpty())
	{
		if (strItem.GetLength())
		{
			if (m_bSetFont)
			{
				CFont cf;
				cf.CreateFont(12,0,0,0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
                      OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
                      ANTIALIASED_QUALITY, DEFAULT_PITCH, strItem);
				CFont * pOldFont = pDC->SelectObject(&cf);
				int nBkMode = pDC->SetBkMode(TRANSPARENT);
				pDC->DrawText(strItem, prcText, DT_SINGLELINE|DT_VCENTER);
				pDC->SetBkMode(nBkMode);
				pDC->SelectObject(pOldFont);
			}
			else
			{
				CFont * pOldFont = pDC->SelectObject(GetFont());
				int nBkMode = pDC->SetBkMode(TRANSPARENT);
				CSize szFont = pDC->GetTextExtent(strItem);
				pDC->DrawText(strItem, prcText, DT_SINGLELINE|DT_VCENTER);
				pDC->SetBkMode(nBkMode);
				pDC->SelectObject(pOldFont);
			}
		}
	}
}

void CEXDropListComboBox::MeasureItem(LPMEASUREITEMSTRUCT lpMIS)
{
 	int nWidth = lpMIS->itemWidth;
 	int nHeight = lpMIS->itemHeight;

	if( lpMIS->itemID == -1 ) return;
}

void CEXDropListComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{

	ASSERT(lpDrawItemStruct->CtlType == ODT_COMBOBOX);

	if (lpDrawItemStruct->itemID == -1) return;

	CDC dc;
	dc.Attach(lpDrawItemStruct->hDC);

	COLORREF crOldTextColor = dc.GetTextColor();
	COLORREF crOldBkColor = dc.GetBkColor();

	if (lpDrawItemStruct->itemAction & ODA_DRAWENTIRE )
	{
		DrawFrame(NULL);
	}

	if (/*(lpDrawItemStruct->itemAction | ODA_SELECT) &&*/
		(lpDrawItemStruct->itemState  & ODS_SELECTED))
	{
		dc.SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
		dc.SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
		dc.FillSolidRect(&lpDrawItemStruct->rcItem, m_crListFocus);
		dc.DrawFocusRect(&lpDrawItemStruct->rcItem);
	}
	else
	{
		dc.FillSolidRect(&lpDrawItemStruct->rcItem, m_crListNormal);
	}

	CRect rcText(lpDrawItemStruct->rcItem);

	if (rcText.left)
		rcText.InflateRect(rcText.left, 0);

	if (rcText.top)
		rcText.InflateRect(0, rcText.top);
		
	rcText.DeflateRect(5, 2, 2, 5);
	MyDrawTextEx(&dc, lpDrawItemStruct->itemID, &rcText);
	dc.SetTextColor(crOldTextColor);
	dc.SetBkColor(crOldBkColor);

	dc.Detach();
}

void CEXDropListComboBox::PreSubclassWindow()
{
	ModifyStyle(0, WS_OVERLAPPED);

	CComboBox::PreSubclassWindow();

	ASSERT(GetStyle() & CBS_DROPDOWNLIST);
	ASSERT(GetStyle() & CBS_OWNERDRAWVARIABLE);
	ASSERT(GetStyle() & CBS_HASSTRINGS);

	RecalcDropWidth();
}

BOOL CEXDropListComboBox::SetComboBgBitmaps(UINT nBkgndID, UINT nBtnID, 
                                            int nCount, COLORREF crBkgnd, 
                                            int nTopHeight/* = 0*/, 
                                            int nBottomHeight/* = 0*/, 
                                            int nLeftWidth/* = 0*/, 
                                            int nRightWidth/* = 20*/)
{
	m_nComboTopHeight = nTopHeight;
	m_nComboBottomHeight = nBottomHeight;
	m_nComboLeftWidth = nLeftWidth;
	m_nComboRightWidth = nRightWidth;

	m_nBtnID = nBtnID;
	m_nComboBkgndID = nBkgndID;
	m_nComboNumOfBgPics  = nCount; 

	m_crComboBkgnd = crBkgnd;

	CBitmap bmpTemp;
	if( !bmpTemp.LoadBitmap(m_nComboBkgndID) )
		return FALSE;

	CBitmap bmpBtn;
	if( !bmpBtn.LoadBitmap(m_nBtnID) )
		return FALSE;

	m_bmpBkgnd.DeleteObject();

	m_bSetComboBg = TRUE;

	if( !InitBgBitmap( bmpTemp, bmpBtn, normal, m_nComboNumOfBgPics) ) 
		return FALSE;

	if( !InitBgBitmap( bmpTemp, bmpBtn, focus, m_nComboNumOfBgPics) )
		return FALSE;

	if( !InitBgBitmap( bmpTemp, bmpBtn, select, m_nComboNumOfBgPics) )
		return FALSE;

	if( !InitBgBitmap( bmpTemp, bmpBtn, disable, m_nComboNumOfBgPics) )
		return FALSE;

	return TRUE;
}

BOOL CEXDropListComboBox::InitBgBitmap(CBitmap & src, CBitmap & bmpBtn, 
                                       int index, int count)
{
	CDC * pDC = GetDC();

	CDC memDC;
	memDC.CreateCompatibleDC(pDC);

	CDC srcDC;
	srcDC.CreateCompatibleDC(pDC);

	CBitmap* pOldBitmap1;
	pOldBitmap1 = srcDC.SelectObject(&src);

	BITMAP bmpinfo;
	src.GetBitmap(&bmpinfo);
	int bmpWidth = bmpinfo.bmWidth / count;
	int bmpHeight = bmpinfo.bmHeight;
	int orix = bmpWidth * (index < count ? index : 0);

	CRect rc;
	//	GetClientRect(rc);
	GetWindowRect(rc);
	rc.OffsetRect(-rc.left, -rc.top);

	CBitmap dist;
	dist.CreateCompatibleBitmap(pDC,rc.Width(),rc.Height());

	CBitmap* pOldBitmap2;
	pOldBitmap2 = memDC.SelectObject(&dist);

	memDC.FillSolidRect(rc, m_crComboBkgnd);

	// entireimage
	if (!memDC.TransparentBlt(m_nComboLeftWidth,
		m_nComboTopHeight,
		rc.Width()  - ( m_nComboLeftWidth + m_nComboRightWidth ) ,
		rc.Height() -  ( m_nComboTopHeight + m_nComboBottomHeight) ,
		&srcDC,
		orix + m_nComboLeftWidth,
		m_nComboTopHeight,
		bmpWidth - ( m_nComboLeftWidth + m_nComboRightWidth ) ,
		bmpHeight - ( m_nComboTopHeight + m_nComboBottomHeight ) , m_crComboBkgnd))
		return FALSE;

	// topbar
	if (!memDC.TransparentBlt(m_nComboLeftWidth,0, rc.Width() - (m_nComboLeftWidth + m_nComboRightWidth), m_nComboTopHeight,
		&srcDC,orix + m_nComboLeftWidth, 0, bmpWidth - ( m_nComboLeftWidth + m_nComboRightWidth) , m_nComboTopHeight, m_crComboBkgnd))
		return FALSE;

	// bottombar
	if (!memDC.TransparentBlt(m_nComboLeftWidth, rc.bottom - m_nComboBottomHeight, rc.Width() - ( m_nComboLeftWidth + m_nComboRightWidth), m_nComboBottomHeight,
		&srcDC,orix + m_nComboLeftWidth,bmpHeight - m_nComboBottomHeight,bmpWidth - ( m_nComboLeftWidth + m_nComboRightWidth) , m_nComboBottomHeight, m_crComboBkgnd ))
		return FALSE;

	// sidebar
	if (!memDC.TransparentBlt(0,m_nComboTopHeight,m_nComboLeftWidth,rc.bottom - m_nComboTopHeight - m_nComboBottomHeight ,
		&srcDC, orix,m_nComboTopHeight, m_nComboLeftWidth, bmpHeight - ( m_nComboTopHeight + m_nComboBottomHeight ) , m_crComboBkgnd))
		return FALSE;

	if (!memDC.TransparentBlt(rc.right - m_nComboRightWidth ,m_nComboTopHeight,m_nComboRightWidth,rc.bottom - m_nComboTopHeight - m_nComboBottomHeight ,
		&srcDC, orix +  bmpWidth - m_nComboRightWidth,m_nComboTopHeight, m_nComboRightWidth, bmpHeight - m_nComboTopHeight - m_nComboBottomHeight , m_crComboBkgnd))
		return FALSE;

	// lefttop,leftbottom,righttop,rightbottom
	if( !memDC.BitBlt(0, 0, m_nComboLeftWidth, m_nComboTopHeight, &srcDC, orix, 0, SRCCOPY) )
		return FALSE;

	if( !memDC.BitBlt(0,rc.bottom - m_nComboBottomHeight, m_nComboLeftWidth, m_nComboBottomHeight, 
		&srcDC,orix,bmpHeight - m_nComboBottomHeight, SRCCOPY) )
		return FALSE;

	if( !memDC.BitBlt(rc.right - m_nComboRightWidth, 0, m_nComboRightWidth, m_nComboTopHeight, 
		&srcDC,orix + bmpWidth - m_nComboRightWidth, 0, SRCCOPY) )
		return FALSE;

	if( !memDC.BitBlt(rc.right - m_nComboRightWidth, rc.bottom - m_nComboBottomHeight,m_nComboRightWidth, m_nComboBottomHeight,
		&srcDC,orix + bmpWidth - m_nComboRightWidth, bmpHeight - m_nComboBottomHeight, SRCCOPY) )
		return FALSE;

	bmpBtn.GetBitmap(&bmpinfo);
	int bmpBtnWidth = bmpinfo.bmWidth / count;
	int bmpBtnHeight = bmpinfo.bmHeight;
	int Btnorix = bmpBtnWidth * (index < count ? index : 0);

	CDC bmpBtnDC;
	bmpBtnDC.CreateCompatibleDC(pDC);

	CBitmap * pOldBmpBtn = NULL;
	pOldBmpBtn = bmpBtnDC.SelectObject(&bmpBtn);

	int nRightWidth = m_nComboRightWidth-1;

	int nOffX = rc.Width()-m_nComboRightWidth+((nRightWidth-bmpBtnWidth)/2);
	int nOffY = (rc.Height()-bmpBtnHeight)/2+1;

	memDC.TransparentBlt(nOffX, nOffY, bmpBtnWidth, bmpBtnHeight, &bmpBtnDC, Btnorix, 0, bmpBtnWidth, bmpBtnHeight, /*m_crComboBkgnd*/m_crTransparent);

	if (!m_bmpBkgnd.GetSafeHandle())
		m_bmpBkgnd.CreateCompatibleBitmap(pDC, rc.Width()*count, rc.Height());

	CDC dcBkgnd;
	dcBkgnd.CreateCompatibleDC(pDC);

	CBitmap * pOldBitmap3 = dcBkgnd.SelectObject(&m_bmpBkgnd);

	dcBkgnd.BitBlt(rc.Width()*index, 0, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY);

	bmpBtnDC.SelectObject(pOldBmpBtn);
	srcDC.SelectObject(pOldBitmap1);
	memDC.SelectObject(pOldBitmap2);
	dcBkgnd.SelectObject(pOldBitmap3);

	ReleaseDC(pDC);
	ReleaseDC(&srcDC);
	ReleaseDC(&memDC);
	ReleaseDC(&dcBkgnd);

	return TRUE;
}

void CEXDropListComboBox::OnSize(UINT nType, int cx, int cy)
{
	CComboBox::OnSize(nType, cx, cy);

	if (IsWindow(GetSafeHwnd()) && m_bSetComboBg)
	{
		SetComboBgBitmaps(m_nComboBkgndID, m_nBtnID, m_nComboNumOfBgPics, 
                      m_crComboBkgnd, m_nComboTopHeight, m_nComboBottomHeight, 
                      m_nComboLeftWidth, m_nComboRightWidth);
	}
}

void CEXDropListComboBox::OnCbnCloseup()
{
 	m_bSelect = FALSE;
	Invalidate();
}

void CEXDropListComboBox::OnCbnDropdown()
{
	RecalcDropWidth();
 	m_bSelect = TRUE;
	Invalidate();
}

void CEXDropListComboBox::RecalcDropWidth()
{
	// Reset the dropped width
	int nNumEntries = GetCount();
	int nWidth = 0;
	CString str;

	CClientDC dc(this);
	int nSave = dc.SaveDC();
	dc.SelectObject(GetFont());

	int nScrollWidth = 10;
	if (GetStyle() & WS_VSCROLL)
		nScrollWidth = ::GetSystemMetrics(SM_CXVSCROLL);

	for (int i = 0; i < nNumEntries; i++)
	{
		GetLBText(i, str);
		int nLength = dc.GetTextExtent(str).cx + 4 + nScrollWidth;
		nWidth = max(nWidth, nLength);

		SetItemHeight(i, dc.GetTextExtent(str).cy+8);
	}

	// Add margin space to the calculations
	nWidth += dc.GetTextExtent(_T("0")).cx;

	int nHeight = dc.GetTextExtent(_T("0")).cy+4;
	SetItemHeight(-1, nHeight /*> 23 ? nHeight : 23*/);

	dc.RestoreDC(nSave);
	SetDroppedWidth(nWidth);
}

BOOL CEXDropListComboBox::OnEraseBkgnd(CDC* pDC)
{
  if(!m_bSetComboBg)
	  return CComboBox::OnEraseBkgnd(pDC);
  else
  	  return FALSE;
}

void CEXDropListComboBox::OnNcPaint()
{
  if(!m_bSetComboBg)
    CComboBox::OnNcPaint();
  else
	  DrawFrame(NULL);
}

void CEXDropListComboBox::OnPaint()
{
  if(!m_bSetComboBg)
    CComboBox::OnPaint();
  else
  {
    CPaintDC dc(this); // device context for painting
	  DrawFrame(&dc);
  }

}

void CEXDropListComboBox::SetListColor(COLORREF crNoral, COLORREF crFocus)
{
	m_crListNormal = crNoral;
	m_crListFocus = crFocus;

	Invalidate(FALSE);
}

BOOL CALLBACK EnumFontProc (LPLOGFONT lplf, LPTEXTMETRIC lptm, 
                            DWORD dwType, LPARAM lpData)	
{	
	CComboBox *pThis = reinterpret_cast<CComboBox*>(lpData);

	int index = pThis->AddString(lplf->lfFaceName);
	ASSERT(index!=-1);

	int maxLen = lptm->tmMaxCharWidth * lstrlen(lplf->lfFaceName);
	int ret = pThis->SetItemData (index, dwType); 

	ASSERT(ret!=-1);

	return TRUE;
}

void CEXDropListComboBox::SetFontList(CString strDefaultFont)
{
	ResetContent();

	CClientDC dc(this);		
	EnumFonts (dc, 0,(FONTENUMPROC) EnumFontProc,(LPARAM)this); //Enumerate font

	SelectString(-1, strDefaultFont);

	m_bSetFont = TRUE;
}



BOOL CEXDropListComboBox::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
	return CComboBox::OnMouseWheel(nFlags, zDelta, pt);
//	return TRUE;
}
